# -*- coding: utf-8 -*
import ai
import collection
import platform
import gateway
import db
import os
import json
import subprocess
import threading
import queue
import log
from concurrent.futures import ThreadPoolExecutor
from gateway.gateway import interval as inter
from utils.enums import DeviceName, SystemType
from utils.csv import gen_csv
from tuning import *

from typing import List, Any, Dict
from art import tprint


IS_TEST = False
interval = -1            # 收集数据的时间间隔
q = queue.Queue()        # 收集数据和向数据库中插入数据的管道
dc = None                # 数据库实例
logger = None            # 日志模块实例


def collect_data(debug: bool) -> List[float] or None:
    """使用linux命令收集系统性能数据存入管道之中"""
    if platform.system() == "Windows":
        global IS_TEST
        IS_TEST = True

    c = None
    c_list = []
    threads = []
    for Collector in collection.Collectors:
        c = Collector(IS_TEST)
        c_list.append(c)
        t = threading.Thread(target=c.collect, daemon=True)
        t.start()
        threads.append(t)
    for t in threads:
        t.join()
    for c in c_list:
        c.gather()

    rsp = c.get_metrics()[:]
    c.clear()
    if not debug:
        q.put(rsp)
        threading.Timer(interval, collect_data, [False]).start()
    else:
        return rsp


def setup_database(config: Dict) -> Any:
    """初始化数据库"""
    retention = config["retention"]
    name = config["name"]
    host = config["host"]
    port = config["port"]
    return db.DataBase(retention_time=retention, dbname=name, host=host, port=port)


def setup_gateway(config: Dict, datas: List[float]) -> Any:
    """初始化网关接口"""
    host = config["host"]
    port = config["port"]
    debug = config["debug"]
    return gateway.Gateway(data_list=datas, host=host, port=port, debug=debug)


def setup_logger(config: Dict) -> Any:
    """初始化日志模块"""
    level = config["level"]
    color = config["color"]
    return log.Logger(__name__, color, level).get_logger()


def setup_web(logger) -> None:
    """开启web前端可视化界面"""
    sh = os.path.join(os.path.abspath("."), "scripts", "web.sh")
    subprocess.run(["bash", sh], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    logger.info("You can now view your frontend app in your browser: http://localhost:8501.")


if __name__ == "__main__":
    module = "module.json"
    config_path = os.path.join(os.path.abspath("."), "config", module)
    with open(config_path, "r", encoding="utf-8") as f:
        content = f.read()
        module_config = json.loads(content)

    if module_config["debug"]:
        if module_config["collection"]["start"]:
            data = collect_data(True)
        if module_config["database"]["start"]:
            dbconfig = module_config["database"]
            dc = setup_database(dbconfig)
            if module_config["gen_csv"]:
                gen_csv(dc, "nginx.csv")
        if module_config["gateway"]["start"] and module_config["collection"]["start"]:
            gateway_config = module_config["gateway"]
            gateway = setup_gateway(gateway_config, data)
            gateway.run()
        if module_config["ai"]["identify"]["start"]:
            identifier = ai.AutoIdentifier()
            scene = identifier.detect([])
            print(scene)
    else:
        tprint("Kylin-Tuning")
        interval = module_config["collection"]["interval"]
        timer = threading.Timer(interval, collect_data, [False])
        timer.setDaemon(True)
        timer.start()

        aiconfig = module_config["ai"]
        tuning_num = aiconfig["tuning"]["num"]

        dbconfig = module_config["database"]
        dc = setup_database(dbconfig)

        logger_config = module_config["logger"]
        logger = setup_logger(logger_config)

        webber_thread = threading.Thread(target=setup_web, args=(logger, ))
        webber_thread.setDaemon(True)
        webber_thread.start()

        identifier = ai.AutoIdentifier()

        with ThreadPoolExecutor() as pool:
            while True:
                try:
                    data = q.get()
                    cpu = data[inter["cpu"][0]:inter["cpu"][1]]
                    disk = data[inter["disk"][0]:inter["disk"][1]]
                    memory = data[inter["memory"][0]:inter["memory"][1]]
                    network = data[inter["network"][0]:inter["network"][1]]

                    # 向数据库中存入数据
                    pool.submit(dc.insert, cpu, DeviceName.CPU)
                    pool.submit(dc.insert, disk, DeviceName.DISK)
                    pool.submit(dc.insert, memory, DeviceName.MEM)
                    pool.submit(dc.insert, network, DeviceName.NET)
                    pool.submit(dc.insert, data, DeviceName.SUMMARY)

                    # 自动识别当前系统的场景
                    future = pool.submit(identifier.detect, data)
                    logger.info(f"The current system scenario is: {future.result()}")
                    if aiconfig["tuning"]["start"] and tuning_num != 0:
                        tuning_num -= 1
                        if future.result() == "mysql":
                            tuner = MysqlTuner()
                            tuner.plain_software_layer_tune()
                            tuner.plain_system_layer_tune(SystemType.VM, 1)
                            tuner.q_learning_system_layer_tune()
                        else:
                            pass
                except KeyboardInterrupt:
                    print("")
                    logger.info("---Kylin-Tuning stop running---")
                    timer.cancel()
                    pool.shutdown()
                    exit(0)
